/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package cz.muni.fi.pb138.xml.wrda.dao;

import com.thoughtworks.xstream.XStream;
import cz.muni.fi.pb138.xml.wrda.core.Wsdl;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.basex.core.BaseXException;
import org.basex.core.Context;
import org.basex.core.cmd.CreateDB;
import org.basex.core.cmd.DropDB;
import org.basex.core.cmd.Open;
import org.basex.core.cmd.XQuery;
import org.basex.query.QueryException;
import org.basex.query.QueryProcessor;

/**
 *
 * @author N
 */
public class WsdlDaoImpl implements WsdlDao{
    
    private Context dbC;
    private final static Logger LOGGER = Logger.getLogger(WsdlDaoImpl.class.getName());
    private XStream xstream;
    
    
    public WsdlDaoImpl(){
        this.dbC = new Context();
        xstream = new XStream();
        setxStreamAliases();
        try{
            Properties prop = new Properties();
            prop.load(this.getClass().getResourceAsStream("/config.properties"));
            
            new Open(prop.getProperty("db.wsdl.name")).execute(dbC);
        } catch (Exception e){
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "Cannot open WSDL database", e);
        }
    }
    
    @Override
    public void save(Wsdl data){

        String query = MessageFormat.format("insert node {0} into {1}", xstream.toXML(data), "/" + WsdlEntries.class.getSimpleName());
        

        try {
            new XQuery(query).execute(this.dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "Cannot insert data into WSDL database.", ex);
        }
    }
    
    @Override
    public void delete(Wsdl data){
        
    }
    
    @Override
    public List<Wsdl> getAllEntries() {
        String baseXResult = "";
        String query = MessageFormat.format(
                "<{0}> '{' for $wsdl in /{0}/{1} return $wsdl '}' </{0}>", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName());

        try {
            baseXResult = new XQuery(query).execute(dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "BaseX query failed in finding all queries.", ex);
        }

        if (baseXResult.equals("")) {
            return new ArrayList<Wsdl>();
        }

        WsdlEntries ret = (WsdlEntries) xstream.fromXML(baseXResult);

        return ret.list;
    }
    
    @Override
    public void printAll(){
        try {
            System.out.println(new XQuery("/").execute(dbC));
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "Cannot print WSDLs records.", ex);
        }
    }
    
    private void setxStreamAliases() {
        xstream.alias(Wsdl.class.getSimpleName(), Wsdl.class);
        xstream.alias(WsdlEntries.class.getSimpleName(), WsdlEntries.class);
        xstream.addImplicitCollection(WsdlEntries.class, "list");
    }
    
    @Override
    public Object getAllEntriesDistinctNames() {
        String baseXResult = "";
   
        String query = MessageFormat.format(
                "<{0}> '{' for $wsdl in distinct-values(/{0}/{1}/fileName/text()) return (/{0}/{1}[fileName = $wsdl])[last()] '}' </{0}>", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName());

        try {
            baseXResult = new XQuery(query).execute(dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "BaseX fail in query.", ex);
        }

        if (baseXResult.equals("")) {
            return new ArrayList<Wsdl>();
        }

        WsdlEntries ret = (WsdlEntries) xstream.fromXML(baseXResult);

        return ret.list;
    }
    
    @Override
    public Object getAllEntriesByFileName(String fileName) {
        String baseXResult = "";

        String query = MessageFormat.format(
                "<{0}> '{' for $wsdl in /{0}/{1} where $wsdl/fileName = ''{2}''  return $wsdl '}' </{0}>", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName(), fileName);

        try {
            baseXResult = new XQuery(query).execute(dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "BaseX query failed in finding all queries.", ex);
        }

        if (baseXResult.equals("")) {
            return new ArrayList<Wsdl>();
        }

        WsdlEntries ret = (WsdlEntries) xstream.fromXML(baseXResult);

        return ret.list;
    }
    
   @Override
    public void deleteAllEntryByName(String fileName) {

        String query = MessageFormat.format(
                "delete node /{0}/{1}[fileName = ''{2}'']", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName(), fileName);

        QueryProcessor processor = new QueryProcessor(query, dbC);
        try {
            processor.execute();
        } catch (QueryException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "Can't delete entry: " + fileName, ex);
        }
    }
    
    @Override
    public void deleteEntryByTimeStamp(String timeStamp) {

        String query = MessageFormat.format(
                "delete node /{0}/{1}[timeStamp = {2}]", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName(), timeStamp);

        QueryProcessor processor = new QueryProcessor(query, dbC);
        try {
            processor.execute();
        } catch (QueryException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "Can't delete entry: " + timeStamp, ex);
        }
    }

    @Override
    public Wsdl getEntryByTimestamp(String timeStamp) {
        String baseXResult = "";

        String query = MessageFormat.format(
                "<{0}> '{' for $wsdl in /{0}/{1} where $wsdl/timeStamp = {2}  return $wsdl '}' </{0}>", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName(), timeStamp);

        try {
            baseXResult = new XQuery(query).execute(dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "BaseX query failed in finding all queries.", ex);
        }

        if (baseXResult.equals("")) {
            return null;
        }

        WsdlEntries ret = (WsdlEntries) xstream.fromXML(baseXResult);

        return ret.list.get(0);
    }
    
    @Override
    public Object getEntryByFileNameAndTimeStamp(String fileName, String timeStamp) {
        String baseXResult = "";

        String query = MessageFormat.format(
                "<{0}> '{' for $wsdl in /{0}/{1} where $wsdl/fileName = ''{2}'' and $wsdl/timeStamp = {3}  return $wsdl '}' </{0}>", WsdlEntries.class.getSimpleName(), Wsdl.class.getSimpleName(), fileName, timeStamp);

        try {
            baseXResult = new XQuery(query).execute(dbC);
        } catch (BaseXException ex) {
            Logger.getLogger(WsdlDaoImpl.class.getName()).log(Level.SEVERE, "BaseX query failed in finding all queries.", ex);
        }

        if (baseXResult.equals("")) {
            return new ArrayList<Wsdl>();
        }

        WsdlEntries ret = (WsdlEntries) xstream.fromXML(baseXResult);

        return ret.list.get(0);
    }
    
    private class WsdlEntries {

        private List<Wsdl> list;

        public WsdlEntries() {
            list = new ArrayList<Wsdl>();
        }

        public void add(Wsdl wsdl) {
            list.add(wsdl);
        }

        public List<Wsdl> getList() {
            return list;
        }

        public void setList(List<Wsdl> list) {
            this.list = list;
        }

    }
    
}
